﻿#include "mode2_keyboard.hpp"
#include "mode_data.hpp"
#include "../../liblive2d/include/catlive2d.hpp"
#include "../../libcat/include/cat-window.hpp"
#include "../../libcat/include/cat-audio.hpp"

namespace{
	keyboard * s_instance = NULL;

	POINT point;
}

keyboard* keyboard::GetInstance()
{
	if (s_instance == NULL)
	{
		s_instance = new keyboard();
	}
	return s_instance;
}

void keyboard::ReleaseInstance()
{
	if (s_instance != NULL)
	{
		delete s_instance;
	}
	s_instance = NULL;
}

void keyboard::Init(Json::Value cfg)
{
	renderWindowWidth = cfg["decoration"]["window_size"][0].asInt();
	renderWindowHeight = cfg["decoration"]["window_size"][1].asInt();
	cat_set_gui_size(renderWindowWidth, renderWindowHeight);

	std::string standard_module_path;
	for (auto entry = cfg["plugins"]["mode_ex"].begin(); entry != cfg["plugins"]["mode_ex"].end(); entry++)
	{
		if ((*entry)["module_id"].asInt() == 2) {
			standard_module_path = (*entry)["module_data_path"].asCString();
			break;
		}
	}
	
	const char* data = ModeData::LoadFileAsBytes(standard_module_path.c_str());
	if (data == NULL)
	{
		isInit = false;
		return;
	}
	JSONCPP_STRING error;
	Json::CharReaderBuilder json_builder;
	Json::Value root;
	Json::CharReader* json_reader = json_builder.newCharReader();
	bool parsingSuccessful = json_reader->parse(data, data + strlen(data), &root, &error);

	if (!parsingSuccessful) {
		return;
	}
	delete json_reader;
	delete data;

	key_clock.restart();

	std::string mode_path = standard_module_path.substr(0, standard_module_path.find_last_of("/") + 1);
	if (mode_path.size() == 0) {
		mode_path = standard_module_path.substr(0, standard_module_path.find_last_of("\\") + 1);
	}

	bg.setTexture(ModeData::load_texture(mode_path+"bg.png"));
	cat.setTexture(ModeData::load_texture(mode_path + "cat.png"));
	left_up.setTexture(ModeData::load_texture(mode_path + "lefthand/leftup.png"));
	right_up.setTexture(ModeData::load_texture(mode_path + "righthand/rightup.png"));

	int index = 0;
	while (!root["keyboard"]["lefthand"][index].isNull()) {
		std::string imgpath = mode_path + "/lefthand/" + std::to_string(index) + ".png";
		int key_index = 0;
		while (!root["keyboard"]["lefthand"][index][key_index].isNull()) {
			int keycode = root["keyboard"]["lefthand"][index][key_index].asInt();
			left_hands_down[imgpath].keys.push_back(keycode);
			states[keycode] = false;
			key_index++;
		}
		ModeData::load_texture2(imgpath);
		index++;
	}

	index = 0;
	while (!root["keyboard"]["righthand"][index].isNull()) {
		std::string imgpath = mode_path + "/righthand/" + std::to_string(index) + ".png";
		int key_index = 0;
		while (!root["keyboard"]["righthand"][index][key_index].isNull()) {
			int keycode = root["keyboard"]["righthand"][index][key_index].asInt();
			right_hands_down[imgpath].keys.push_back(keycode);
			states[keycode] = false;
			key_index++;
		}
		ModeData::load_texture2(imgpath);
		index++;
	}

	index = 0; 
	while (!root["keyboard"]["keyboard"][index].isNull()) {
		std::string imgpath = mode_path + "/keyboard/" + std::to_string(index) + ".png";
		int key_index = 0;
		while (!root["keyboard"]["keyboard"][index][key_index].isNull()) {
			int keycode = root["keyboard"]["keyboard"][index][key_index].asInt();
			keys[imgpath].keys.push_back(keycode);
			states[keycode] = false;
			key_index++;
		}
		ModeData::load_texture2(imgpath);
		index++;
	}
	index = 0;
	while (!root["keyboard"]["face"][index].isNull()) {
		std::string imgpath = mode_path + "/face/" + std::to_string(index) + ".png";
		int key_index = 0;
		while (!root["keyboard"]["face"][index][key_index].isNull()) {
			int keycode = root["keyboard"]["face"][index][key_index].asInt();
			faces[imgpath].keys.push_back(keycode);
			states[keycode] = false;
			key_index++;
		}
		ModeData::load_texture2(imgpath);
		index++;
	}

	index = 0;
	while (!root["keyboard"]["sounds"][index].isNull()) {
		std::string imgpath = mode_path + "/sounds/" + std::to_string(index) + ".flac";
		int key_index = 0;
		while (!root["keyboard"]["sounds"][index][key_index].isNull()) {
			int keycode = root["keyboard"]["sounds"][index][key_index].asInt();
			sounds[imgpath].keys.push_back(keycode);
			states[keycode] = false;
			key_index++;
		}
		index++;
	}

	index = 0;
	while (!root["keyboard"]["l2d_motion"][index].isNull()) {
		std::string imgpath = std::to_string(index);
		int key_index = 0;
		while (!root["keyboard"]["l2d_motion"][index][key_index].isNull()) {
			int keycode = root["keyboard"]["l2d_motion"][index][key_index].asInt();
			motions[imgpath].keys.push_back(keycode);
			states[keycode] = false;
			key_index++;
		}
		index++;
	}
	index = 0;
	while (!root["keyboard"]["l2d_expression"][index].isNull()) {
		std::string imgpath = std::to_string(index);
		int key_index = 0;
		while (!root["keyboard"]["l2d_expression"][index][key_index].isNull()) {
			int keycode = root["keyboard"]["l2d_expression"][index][key_index].asInt();
			expression[imgpath].keys.push_back(keycode);
			states[keycode] = false;
			key_index++;
		}
		index++;
	}

	std::string l2dmodelPath = mode_path + "cat_model/";
	cat_live2d_load_model(l2dmodelPath.c_str(), "cat.model3.json");

	isInit = true;

	Update(cfg);
}

void keyboard::Update(Json::Value cfg)
{
	renderWindowWidth = cfg["decoration"]["window_size"][0].asInt();
	renderWindowHeight = cfg["decoration"]["window_size"][1].asInt();

	renderTexture.create(renderWindowWidth, renderWindowHeight, false);
	renderTexture.setSmooth(true);
	renderSprite.setTexture(renderTexture.getTexture());
	renderSprite.setTextureRect(sf::IntRect(sf::Vector2i(0, 0), sf::Vector2i(renderTexture.getSize().x, renderTexture.getSize().y)));

	is_emoticonkeep = cfg["main_decoration"]["motion_keep"].asBool();
	is_soundkeep = cfg["main_decoration"]["sound_keep"].asBool();

	isLive2d = cfg["main_decoration"]["l2d"].asBool();

	if (isLive2d) {

		l2d_correct = cfg["decoration"]["l2d_correct"].asFloat();
		l2d_offset_x = cfg["decoration"]["l2d_offset"][0].asFloat();
		l2d_offset_y = cfg["decoration"]["l2d_offset"][1].asFloat();

		float speed = cfg["main_decoration"]["l2d_spead"].asFloat();
		l2d_random_motion = cfg["main_decoration"]["l2d_random_motion"].asBool();
		l2d_random_expression = cfg["main_decoration"]["l2d_random_expression"].asBool();
		cat_live2d_translate(l2d_offset_x, l2d_offset_y);
		cat_live2d_scale(l2d_correct, l2d_correct);
		cat_live2d_speed(speed);
		cat_live2d_set_random_motion(l2d_random_motion, l2d_random_expression);

		cat_live2d_resize(renderWindowWidth, renderWindowHeight);
	}

	cat_audio_set_silent(cfg["main_decoration"]["silent"].asBool());
}

void keyboard::Draw(void* _window)
{
	cat_window* window = (cat_window*)_window;
	if (isInit) {
		renderTexture.clear(sf::Color(0, 0, 0, 0));

		if (isLive2d) {
			renderTexture.draw(bg);
			cat_live2d_run(NULL);
			drawKey(renderTexture);
			drawLeftHand(renderTexture);
			drawRightHand(renderTexture);
			drawFace(renderTexture);
			playMotion(); 
			playExpression();
		}
		else {
			drawCat(renderTexture);
			drawFace(renderTexture);
			drawKey(renderTexture);
			drawLeftHand(renderTexture);
			drawRightHand(renderTexture);
		}
		playSound();
		

		renderTexture.display();
		window->window->draw(renderSprite);
	}

}

void keyboard::Release()
{
	ModeData::clear_holder();

	cat_live2d_release_model();

	states.clear();
	left_hands_down.clear();
	right_hands_down.clear();
	keys.clear();
	faces.clear();
	sounds.clear(); 
	motions.clear(); 
	expression.clear();
}

void keyboard::OnKeyPress(const int vk, bool key_up)
{
	if (states.find(vk) != states.end()) {
		states[vk] = !key_up;
	}
}

keyboard::keyboard()
{
	
}

keyboard::~keyboard()
{
	
}

void keyboard::drawCat(sf::RenderTexture& _window)
{
	_window.draw(cat);

	_window.draw(bg);
	
}

void keyboard::drawKey(sf::RenderTexture& _window)
{
	for (auto entry = keys.begin(); entry != keys.end(); entry++) {
		bool flag = true;
		for (auto key_state = (*entry).second.keys.begin(); key_state != (*entry).second.keys.end(); key_state++)
		{
			flag &= states[(*key_state)];
		}

		flag ? (*entry).second.isShow = true : (*entry).second.isShow = false;

		if ((*entry).second.isShow == true) {
			sf::Sprite key;
			key.setTexture(ModeData::load_texture2((*entry).first));
			_window.draw(key);
		}
	}
}

void keyboard::drawLeftHand(sf::RenderTexture& _window)
{
	bool HandUp = true;
	std::string whichHand;
	for (auto entry = left_hands_down.begin(); entry != left_hands_down.end(); entry++) {
		bool flag = true;
		for (auto key_state = (*entry).second.keys.begin(); key_state != (*entry).second.keys.end(); key_state++)
		{
			flag &= states[(*key_state)];
		}

		if (flag && !(*entry).second.isShow) {
			(*entry).second.record = key_clock.getElapsedTime();
		}

		flag ? (*entry).second.isShow = true : (*entry).second.isShow = false;

		if ((*entry).second.isShow)
		{
			if (whichHand.empty()) {
				whichHand = (*entry).first;
			}
			if (left_hands_down[whichHand].record < (*entry).second.record)
			{
				whichHand = (*entry).first;
			}
			HandUp = false;
		}
	}
	cat_live2d_on_left_hand_down_callback(HandUp);

	if (!whichHand.empty()&&left_hands_down[whichHand].isShow) {
		sf::Sprite hand;
		hand.setTexture(ModeData::load_texture2(whichHand));
		_window.draw(hand);
	}

	if (!isLive2d && HandUp)
		_window.draw(left_up);
}

void keyboard::drawRightHand(sf::RenderTexture& _window)
{
	bool HandUp = true; 
	std::string whichHand;
	for (auto entry = right_hands_down.begin(); entry != right_hands_down.end(); entry++) {
		bool flag = true;
		for (auto key_state = (*entry).second.keys.begin(); key_state != (*entry).second.keys.end(); key_state++)
		{
			flag &= states[(*key_state)];
		}

		if (flag && !(*entry).second.isShow) {
			(*entry).second.record = key_clock.getElapsedTime();
		}

		flag ? (*entry).second.isShow = true : (*entry).second.isShow = false;

		if ((*entry).second.isShow)
		{
			if (whichHand.empty()) {
				whichHand = (*entry).first;
			}
			if (right_hands_down[whichHand].record < (*entry).second.record)
			{
				whichHand = (*entry).first;
			}
			HandUp = false;
		}
	}
	cat_live2d_on_right_hand_down_callback(HandUp);

	if (!whichHand.empty()&&right_hands_down[whichHand].isShow) {
		sf::Sprite hand;
		hand.setTexture(ModeData::load_texture2(whichHand));
		_window.draw(hand);
	}

	if (!isLive2d && HandUp)
		_window.draw(right_up);
}

void keyboard::drawFace(sf::RenderTexture& _window)
{
	for (auto entry = faces.begin(); entry != faces.end(); entry++) {
		bool flag = true;
		for (auto key_state = (*entry).second.keys.begin(); key_state != (*entry).second.keys.end(); key_state++)
		{
			flag &= states[(*key_state)];
		}
		flag ? (*entry).second.isShow = true : (*entry).second.isShow = false;

		if (is_emoticonkeep) {
			if ((*entry).second.isShow != (*entry).second.isLastShow) {
				if ((*entry).second.isLastShow)
					(*entry).second.LastShowCount++;
				(*entry).second.isLastShow = (*entry).second.isShow;
			}

			if ((*entry).second.LastShowCount % 2) {
				sf::Sprite key;
				key.setTexture(ModeData::load_texture2((*entry).first));
				_window.draw(key);
			}
		}
		else if ((*entry).second.isShow) {
			sf::Sprite key;
			key.setTexture(ModeData::load_texture2((*entry).first));
			_window.draw(key);
		}
	}
}

void keyboard::playSound()
{
	for (auto entry = sounds.begin(); entry != sounds.end(); entry++) {
		bool flag = true;
		for (auto key_state = (*entry).second.keys.begin(); key_state != (*entry).second.keys.end(); key_state++)
		{
			flag &= states[(*key_state)];
		}

		flag ? (*entry).second.isShow = true : (*entry).second.isShow = false;

		if ((*entry).second.isShow != (*entry).second.isLastShow) {
			if (!(*entry).second.isLastShow)
				(*entry).second.LastShowCount++;
			(*entry).second.isLastShow = (*entry).second.isShow;
		}

		if ((*entry).second.LastShowCount % 2) {
			if ((*entry).second.isShow)
				cat_play_sound((*entry).first.c_str(), is_soundkeep);
			(*entry).second.LastShowCount++;
		}
	}
}

void keyboard::playMotion()
{
	for (auto entry = motions.begin(); entry != motions.end(); entry++) {
		bool flag = true;
		for (auto key_state = (*entry).second.keys.begin(); key_state != (*entry).second.keys.end(); key_state++)
		{
			flag &= states[(*key_state)];
		}
		if (flag == true) {
			cat_live2d_play_motion("CAT_motion", std::stoi((*entry).first));
		}

	}
}

void keyboard::playExpression()
{
	for (auto entry = expression.begin(); entry != expression.end(); entry++) {
		bool flag = true;
		for (auto key_state = (*entry).second.keys.begin(); key_state != (*entry).second.keys.end(); key_state++)
		{
			flag &= states[(*key_state)];
		}

		if (is_emoticonkeep) {
			if (flag != (*entry).second.isLastShow) {
				if (flag)
				{
					(*entry).second.LastShowCount++;
				}
				(*entry).second.isLastShow = flag;
			}

			if ((*entry).second.LastShowCount % 2) {
				if (flag && !(*entry).second.isShow)
				{
					for (auto entry2 = expression.begin(); entry2 != expression.end(); entry2++) {
						(*entry2).second.isShow = false;
					}
					(*entry).second.isShow = true;
					cat_live2d_set_expression_by_id(std::stoi((*entry).first));
				}
				else if (flag)
				{
					cat_live2d_set_expression_by_id(0);
					(*entry).second.isShow = false;
				}
				(*entry).second.LastShowCount++;
			}
		}
		else
		{
			if (flag) {
				cat_live2d_set_expression_by_id(std::stoi((*entry).first));
				(*entry).second.isShow = true;
			}
			else if ((*entry).second.isShow)
			{
				(*entry).second.isShow = false;
				cat_live2d_set_expression_by_id(0);
			}

		}
	}
}


